package dashboard.jedis;

import java.util.Arrays;
import java.util.List;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.Transaction;

public class RedisConnectKindsTests {
//	Jedis jedis  = new Jedis("10.9.19.123", 6379);
	private static Jedis jedis;
    private static ShardedJedis sharding;
    private static ShardedJedisPool pool;
    
	private int count = 1000;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
		List<JedisShardInfo> shards = Arrays.asList(
				new JedisShardInfo("10.9.19.123", 6379),
				new JedisShardInfo("10.9.19.123", 6379)
				);//使用相同的ip:port,仅作测试
 
        jedis = new Jedis("10.9.19.123", 6379);
        sharding = new ShardedJedis(shards);
        pool = new ShardedJedisPool(new JedisPoolConfig(), shards);
    }
    
    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        jedis.disconnect();
        sharding.disconnect();
        pool.destroy();
    }
    
	//普通同步方式
	//最简单和基础的调用方式，每次执行命令后都可以返回结果，标记是否成功
    @SuppressWarnings("unused")
	@Test
	public void test1Normal() {
	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
			String result = jedis.set("n" + i, "n" + i);
	    }
	    long end = System.currentTimeMillis();
	    System.out.println("Simple SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//事务方式
	//保障一个client发起的事务中的命令可以连续的执行，而中间不会插入其他client的命令
	//调用jedis.watch(…)方法来监控key，如果调用后key值发生变化，则整个事务会执行失败。
	//另外，事务中某个操作失败，并不会回滚其他操作。这一点需要注意。还有，我们可以使用discard()方法来取消事务。
	@SuppressWarnings("unused")
	@Test
	public void test2Trans() {
	    long start = System.currentTimeMillis();
	    Transaction tx = jedis.multi();
	    for (int i = 0; i < count; i++) {
	        tx.set("t" + i, "t" + i);
	    }
	    List<Object> results = tx.exec();
	    long end = System.currentTimeMillis();
	    System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//管道
	//要采用异步方式，一次发送多个指令，不同步等待其返回结果
	@SuppressWarnings("unused")
	@Test
	public void test3Pipelined() {
	    Pipeline pipeline = jedis.pipelined();
	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
	        pipeline.set("p" + i, "p" + i);
	    }
//	    事务和管道都是异步模式。在事务和管道中不能同步查询结果。比如下面两个调用，都是不允许的
//	    pipeline.get("p10").get();  tx.get("t1000").get() //不允许
	    System.out.println(pipeline.get("p10"));
	    List<Object> results = pipeline.syncAndReturnAll();
	    long end = System.currentTimeMillis();
	    System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//管道中调用事务
	//Jedis提供的方法而言，是可以做到在管道中使用事务
	@SuppressWarnings("unused")
	@Test
	public void test4combPipelineTrans() {
	    long start = System.currentTimeMillis();
	    Pipeline pipeline = jedis.pipelined();
	    pipeline.multi();
	    for (int i = 0; i < count; i++) {
	        pipeline.set("" + i, "" + i);
	    }
	    pipeline.exec();
	    List<Object> results = pipeline.syncAndReturnAll();
	    long end = System.currentTimeMillis();
	    System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
	}
	
	//分布式直连同步调用
	//分布式直接连接，并且是同步调用，每步执行都返回执行结果。类似地，还有异步管道调用
	@SuppressWarnings("unused")
	@Test
	public void test4ShardNormal(){
		
	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
	        String result = sharding.set("sn" + i, "n" + i);
	    }
	    long end = System.currentTimeMillis();
	    System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//分布式直连异步调用
	@SuppressWarnings("unused")
	@Test
	public void test6shardpipelined() {
	    ShardedJedisPipeline pipeline = sharding.pipelined();
	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
	        pipeline.set("sp" + i, "p" + i);
	    }
	    List<Object> results = pipeline.syncAndReturnAll();
	    long end = System.currentTimeMillis();
	    System.out.println("Pipelined@Sharing SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//分布式连接池同步调用
	//分布式调用代码是运行在线程中，那么上面两个直连调用方式就不合适了，
	//因为直连方式是非线程安全的，这个时候，你就必须选择连接池调用
	@SuppressWarnings("unused")
	@Test
	public void test7shardSimplePool() {
	    ShardedJedis one = pool.getResource();
	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
	        String result = one.set("spn" + i, "n" + i);
	    }
	    long end = System.currentTimeMillis();
	    pool.returnResource(one);
	    System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds");
	}
	
	//分布式连接池异步调用
	@SuppressWarnings("unused")
	@Test
	public void test8shardPipelinedPool() {
	    ShardedJedis one = pool.getResource();
	    ShardedJedisPipeline pipeline = one.pipelined();

	    long start = System.currentTimeMillis();
	    for (int i = 0; i < count; i++) {
	        pipeline.set("sppn" + i, "n" + i);
	    }
	    List<Object> results = pipeline.syncAndReturnAll();
	    long end = System.currentTimeMillis();
	    pool.returnResource(one);
	    System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds");
	}
}

